package main

import (
	"github.com/gin-gonic/gin"
	"go.opentelemetry.io/otel"
	"go.opentelemetry.io/otel/attribute"
	"go.opentelemetry.io/otel/exporters/jaeger"
	"go.opentelemetry.io/otel/propagation"
	"go.opentelemetry.io/otel/sdk/resource"
	tracesdk "go.opentelemetry.io/otel/sdk/trace"
	semconv "go.opentelemetry.io/otel/semconv/v1.18.0"
	"go.opentelemetry.io/otel/trace"
	"time"
)

const (
	traceName = "mxshop-otel"
)

var tp *tracesdk.TracerProvider

func tracerProvider() error {
	// 创建 Jaeger 导出器
	url := "http://192.168.16.168:14268/api/traces"
	jexp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(url)))
	if err != nil {
		return err
	}
	tp = tracesdk.NewTracerProvider(
		tracesdk.WithBatcher(jexp),
		tracesdk.WithResource(resource.NewWithAttributes(
			semconv.SchemaURL, // 必填参数 可以指定是多少版本
			semconv.ServiceNameKey.String("mxshop-user"),
			attribute.String("environment", "dev"),
			attribute.Int("ID", 1),
		)),
	)
	// 设置全局的提取器
	otel.SetTracerProvider(tp)
	// 设置全局的 传播器
	otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
	return nil
}

func Server(c *gin.Context) {
	// 负载 span 的抽取和生成
	ctx := c.Request.Context()

	traceID := c.Request.Header.Get("tracer-id")
	SpanID := c.Request.Header.Get("span-id")

	traceid, _ := trace.TraceIDFromHex(traceID)
	spanid, _ := trace.SpanIDFromHex(SpanID)
	tr := otel.Tracer(traceName)
	spanCtx := trace.NewSpanContext(trace.SpanContextConfig{
		TraceID:    traceid,
		SpanID:     spanid,
		TraceFlags: trace.FlagsSampled,
		Remote:     true,
	})

	// 这块逻辑 是自己构建出来的 不是 传递的
	carrier := propagation.HeaderCarrier{}
	carrier.Set("tracer-id", traceID)
	propagator := otel.GetTextMapPropagator()
	// 构建一个 父context
	pctx := propagator.Extract(ctx, carrier)

	// 传递 父ctx 和 子ctx 生成 父ctx的副本 里面写了 子ctx的信息
	sct := trace.ContextWithRemoteSpanContext(pctx, spanCtx)
	_, span := tr.Start(sct, "gin-server")
	time.Sleep(time.Duration(500) * time.Millisecond)
	span.End()
	c.JSON(200, gin.H{
		"message": "ok",
	})
}

func main() {
	_ = tracerProvider()
	r := gin.Default()
	r.GET("/", func(c *gin.Context) {})
	r.GET("/server", Server)
	r.Run(":8090")
}
